/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package foxmob.mlts.controller.setter;

import foxmob.mlts.component.FileManager;
import foxmob.mlts.component.HTMLDocumentPlusRemove;
import foxmob.mlts.interfaces.setter.MultipleFillInBlankSetterDelegate;
import foxmob.mlts.model.FillInTheBlanksQuestion;
import foxmob.mlts.model.MultipleChoiceQuestion;
import foxmob.mlts.model.MultipleFillInBlankQuestion;
import foxmob.mlts.model.Question;
import foxmob.mlts.model.QuestionPaper;
import foxmob.mlts.model.Section;
import foxmob.mlts.model.Subsection;
import foxmob.mlts.model.TreeObject;
import foxmob.mlts.view.setter.FillInTheBlankSetterPanel;
import foxmob.mlts.view.setter.MultipleChoiceSetterPanel;
import foxmob.mlts.view.setter.MultipleFillInBlankSetterPanel;
import foxmob.mlts.viewcontroller.setter.QuestionForm;
import java.awt.event.ItemEvent;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.HyperlinkEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;

/**
 *
 * @author Lunayo
 */
public class QuestionFormController extends RootModifyFormController implements MultipleFillInBlankSetterDelegate {
    
    private TreeObject tempTreeObject;
    private MultipleChoiceSetterPanel multiple;
    private FillInTheBlankSetterPanel fillin;
    private MultipleFillInBlankSetterPanel multipleFillin;
            
    private static final String MULTIPLE_CHOICE_QUESTION = "Multiple";
    private static final String FILL_IN_BLANK_QUESTION = "Fill In";
    private static final String MULTIPLE_FILL_IN_BLANK_QUESTION = "Multiple Fill In";
    private static final String EDIT_LABEL = "Save Question";
    private static final String ADD_LABEL = "Add Question";
    
    private QuestionForm delegate;
    
    public QuestionFormController(SetterFormController setterFormdelegate ,
            QuestionForm delegate) {
       super(setterFormdelegate);
       this.delegate = delegate;
       initObjects();
       initComboBoxComponents(); 
    }
    
    private void initObjects() {
        multiple = new MultipleChoiceSetterPanel();
        multipleFillin = new MultipleFillInBlankSetterPanel(this);
        fillin = new FillInTheBlankSetterPanel();
    }
    
    public void setDelegate(QuestionForm delegate) {
        this.delegate = delegate;
    }
    
    public QuestionForm getDelegate() {
        return this.delegate;
    }
    
    private void initComboBoxComponents() {
        // Setup combo box item
        delegate.getTypeCombo().addItem(MULTIPLE_CHOICE_QUESTION);
        delegate.getTypeCombo().addItem(FILL_IN_BLANK_QUESTION);
        delegate.getTypeCombo().addItem(MULTIPLE_FILL_IN_BLANK_QUESTION);
    }
    
    public void eventChanged(SetterFormController.ActionEvent status) {
        if (this.currentState == SetterFormController.ActionEvent.ADD_EVENT) {
            delegate.getSaveButton().setText(ADD_LABEL);
            delegate.getDeleteQuestionButton().setVisible(false);
            delegate.getSectionCombo().setEnabled(true);
            delegate.getSubSectionCombo().setEnabled(true);
        } else if (this.currentState == SetterFormController.ActionEvent.EDIT_EVENT) {
            delegate.getSaveButton().setText(EDIT_LABEL);
            delegate.getDeleteQuestionButton().setVisible(true);
            delegate.getSectionCombo().setEnabled(false);
            delegate.getSubSectionCombo().setEnabled(false);
        } 
    }
    
    @Override
    public void setCurrentState(SetterFormController.ActionEvent state) {
        super.setCurrentState(state);
        eventChanged(state);
    }
    
    
    @Override
    public boolean validateInputComponent() {
        super.validateInputComponent();
        String message =  "Please input all of the information";
        if (delegate.getTypeCombo().getSelectedIndex() == 0 ||
                delegate.getSectionCombo().getSelectedIndex() == 0 ||
                delegate.getSubSectionCombo().getSelectedIndex() == 0) {
            JOptionPane.showMessageDialog(null, message);
            return false;
        } else {
            String selectedItem = delegate.getTypeCombo().getSelectedItem().toString();
            if (selectedItem.equals(MULTIPLE_CHOICE_QUESTION)) {
                MultipleChoiceSetterPanel panel = 
                    (MultipleChoiceSetterPanel)delegate.getMainPanel().getComponent(0);
                // validate multiple choice panel component
                if (panel.getQuestionText().equals("") ||
                        panel.getQuestionText().isEmpty()) {
                    panel.getQuestionTextArea().requestFocus();
                    JOptionPane.showMessageDialog(null, message);
                    return false;
                } else {
                    for (int i = 1; i <= panel.getMultipleChoiceCount(); ++i) {
                        JTextField field = panel.getMultipleChoiceTextArea(i);
                        if (field.getText().equals("") ||
                                field.getText().isEmpty()) {
                            field.requestFocus();
                            JOptionPane.showMessageDialog(null, message);
                            return false;
                        }
                    }
                }
            } else if (selectedItem.equals(FILL_IN_BLANK_QUESTION)) {
                FillInTheBlankSetterPanel panel = 
                    (FillInTheBlankSetterPanel)delegate.getMainPanel().getComponent(0);
                // validate fill in the blank panel component
                if (panel.getQuestionText().equals("") ||
                        panel.getQuestionText().isEmpty()) {
                    panel.getQuestionTextArea().requestFocus();
                    JOptionPane.showMessageDialog(null, message);
                    return false;
                } else if (panel.getCorrectAnswer().length == 0) {
                    panel.getCorrectAnswerTextArea().requestFocus();
                    JOptionPane.showMessageDialog(null, message);
                    return false;
                }
            } else if (selectedItem.equals(MULTIPLE_FILL_IN_BLANK_QUESTION)) {
                MultipleFillInBlankSetterPanel panel = 
                    (MultipleFillInBlankSetterPanel)delegate.getMainPanel().getComponent(0);
                // validate fill in the blank panel component
                if (panel.getQuestionText().equals("") ||
                        panel.getQuestionText().isEmpty()) {
                    panel.getQuestionTextArea().requestFocus();
                    JOptionPane.showMessageDialog(null, message);
                    return false;
                }
            }
        }
        return true;
    }
    
    @Override
    public void resetInputComponent() {
        super.resetInputComponent();
        String selectedItem = delegate.getTypeCombo().getSelectedItem().toString();
        if (selectedItem.equals(MULTIPLE_CHOICE_QUESTION)) {
            MultipleChoiceSetterPanel panel = 
                    (MultipleChoiceSetterPanel)delegate.getMainPanel().getComponent(0);
            panel.resetInputComponent();
        } else if (selectedItem.equals(FILL_IN_BLANK_QUESTION)) {
            FillInTheBlankSetterPanel panel = 
                    (FillInTheBlankSetterPanel)delegate.getMainPanel().getComponent(0);
            panel.resetInputComponent();
        } else if (selectedItem.equals(MULTIPLE_FILL_IN_BLANK_QUESTION)) {
            MultipleFillInBlankSetterPanel panel =
                    (MultipleFillInBlankSetterPanel)delegate.getMainPanel().getComponent(0);
            panel.resetInputComponent();
        }
    }
    
    public void updateSectionComboBox() {
        // reset combo box
        delegate.getSectionCombo().removeAllItems();
        delegate.getSectionCombo().addItem("<Section>");
        QuestionPaper record = treeObject.getRecord();
        int j = 1;
        for (Section sec : record.getSections()) {
            delegate.getSectionCombo().addItem(sec);
            if (sec.getID().equals(treeObject.getSection().getID())) {
                delegate.getSectionCombo().setSelectedIndex(j);
            }
            ++j;
        }
    }
    
    public void updateSubSectionComboBox(Section section) {
        // reset combo box
        delegate.getSubSectionCombo().removeAllItems();
        delegate.getSubSectionCombo().addItem("<Subsection>");
        // fill in section combo box
        int j = 1;
        // fill in subsection combo box
        for (Subsection sub : section.getSubsections()) {
            delegate.getSubSectionCombo().addItem(sub);
            if (sub.getID().equals(treeObject.getSubsection().getID())) {
                delegate.getSubSectionCombo().setSelectedIndex(j);
            }
            ++j;
        }
    }
    
    public void updateQuestionComponents(TreeObject obj) {
        Section section = obj.getSection();
        updateSectionComboBox();
        updateSubSectionComboBox(section);
    }
    
    private Question getQuestionComponent() {
        String selectedItem = (String)delegate.getTypeCombo().getSelectedItem();
        if (selectedItem.equals(MULTIPLE_CHOICE_QUESTION)) {
            MultipleChoiceSetterPanel panel = 
                    (MultipleChoiceSetterPanel)delegate.getMainPanel().getComponent(0);
            // construct question
            MultipleChoiceQuestion question = new MultipleChoiceQuestion();
            question.setCorrectAnswer(panel.getCorrectAnswer());
            question.setPossibleAnswers(panel.getPossibleAnswer());
            question.setQuestionText(panel.getQuestionText());
            return question;
        } else if (selectedItem.equals(FILL_IN_BLANK_QUESTION)) {
            FillInTheBlankSetterPanel panel = 
                    (FillInTheBlankSetterPanel)delegate.getMainPanel().getComponent(0);
            FillInTheBlanksQuestion question = new FillInTheBlanksQuestion();
            question.setCorrectAnswer(panel.getCorrectAnswer());
            question.setQuestionText(panel.getQuestionText());
            return question;
        } else if (selectedItem.equals(MULTIPLE_FILL_IN_BLANK_QUESTION)) {
            MultipleFillInBlankSetterPanel panel = 
                    (MultipleFillInBlankSetterPanel)delegate.getMainPanel().getComponent(0);
            MultipleFillInBlankQuestion question = new MultipleFillInBlankQuestion();
            // save all the correct answer before add to question
            saveCorrectAnswer(multipleFillin.getPreviousNumber());
            question.setQuestionText(panel.getQuestionText());
            question.setQuestionDocument(panel.getHTMLDocument());
            question.setCorrectAnswer(panel.getCorrectAnswer()); 
            return question;
        }
        return null;
    }

    public void fillQuestionComponents(TreeObject obj) {
        if (obj.getQuestion() instanceof MultipleChoiceQuestion) {
            delegate.getTypeCombo().setSelectedItem(MULTIPLE_CHOICE_QUESTION);
            MultipleChoiceQuestion question =
                    (MultipleChoiceQuestion)obj.getQuestion();
            MultipleChoiceSetterPanel panel = 
                    (MultipleChoiceSetterPanel)delegate.getMainPanel().getComponent(0);
            panel.setQuestionText(question.getQuestionText());
            panel.setCorrectAnswer(question.getCorrectAnswer());
            panel.setPossibleAnswer(question.getPossibleAnswers());
        } else if (obj.getQuestion() instanceof FillInTheBlanksQuestion) {
            delegate.getTypeCombo().setSelectedItem(FILL_IN_BLANK_QUESTION);
            FillInTheBlanksQuestion question =
                    (FillInTheBlanksQuestion)obj.getQuestion();
            FillInTheBlankSetterPanel panel = 
                    (FillInTheBlankSetterPanel)delegate.getMainPanel().getComponent(0);
            panel.setQuestionText(question.getQuestionText());
            panel.setCorrectAnswer(question.getCorrectAnswer());
        } else if (obj.getQuestion() instanceof MultipleFillInBlankQuestion) {
            delegate.getTypeCombo().setSelectedItem(MULTIPLE_FILL_IN_BLANK_QUESTION);
            MultipleFillInBlankQuestion question =
                    (MultipleFillInBlankQuestion)obj.getQuestion();
            MultipleFillInBlankSetterPanel panel = 
                    (MultipleFillInBlankSetterPanel)delegate.getMainPanel().getComponent(0);
            panel.setHTMLDocument(question.getQuestionDocument());
            panel.setListOfAnswer(question.getCorrectAnswer());
            panel.setCorrectAnswer(1);
        }
    }
    
    private void addQuestionToRecord(QuestionPaper record) {
        FileManager manager = FileManager.getInstanceObject();
        Section section =
            record.getSectionWithID(treeObject.getSection().getID());
        Subsection subsection =
            section.getSubsectionWithID(treeObject.getSubsection().getID());
        if (!validateInputComponent()) {
            return;
        } else if (subsection.isExistQuestion(getQuestionComponent())) {
            // display message box
            String message = "Record existed, please choose another name";
            JOptionPane.showMessageDialog(null, message);
            return;
        }
        try {
            // TODO add your handling code here:
            subsection.addQuestion(getQuestionComponent());
            // Save to file
            manager.saveToFile(record);
            String st ="Question added successfully!";
            JOptionPane.showMessageDialog(null,st);
        } catch (IOException ex) {
            Logger.getLogger(QuestionForm.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    private void editQuestionFromRecord(QuestionPaper record) {
        if (!validateInputComponent()) {
            return;
        } 
        try {
            // TODO add your handling code here:
            FileManager manager = FileManager.getInstanceObject();
            Section section =
                record.getSectionWithID(treeObject.getSection().getID());
            Subsection subsection =
                section.getSubsectionWithID(treeObject.getSubsection().getID());
            Question question = 
                subsection.getQuestionWithID(treeObject.getQuestion().getID());
            if (question instanceof MultipleChoiceQuestion) {
                MultipleChoiceQuestion ques = (MultipleChoiceQuestion) question;
                MultipleChoiceQuestion componentQuestion = 
                        (MultipleChoiceQuestion) getQuestionComponent();
                ques.setQuestionText(componentQuestion.getQuestionText());
                ques.setWeight(componentQuestion.getWeight());
                ques.setCorrectAnswer(componentQuestion.getCorrectAnswer());
                ques.setPossibleAnswers(componentQuestion.getPossibleAnswers());
                ques.setID(treeObject.getQuestion().getID());
                subsection.modifyQuestion(ques);
            } else if (question instanceof FillInTheBlanksQuestion) {
                FillInTheBlanksQuestion ques = (FillInTheBlanksQuestion) question;
                FillInTheBlanksQuestion componentQuestion =
                        (FillInTheBlanksQuestion) getQuestionComponent();
                ques.setQuestionText(componentQuestion.getQuestionText());
                ques.setWeight(componentQuestion.getWeight());
                ques.setCorrectAnswer(componentQuestion.getCorrectAnswer());
                ques.setID(treeObject.getQuestion().getID());
                subsection.modifyQuestion(ques);
            } else if (question instanceof MultipleFillInBlankQuestion) {
                MultipleFillInBlankQuestion ques = 
                        (MultipleFillInBlankQuestion) question;
                MultipleFillInBlankQuestion componentQuestion =
                        (MultipleFillInBlankQuestion) getQuestionComponent();
                ques.setQuestionText(componentQuestion.getQuestionText());
                ques.setWeight(componentQuestion.getWeight());
                ques.setCorrectAnswer(componentQuestion.getCorrectAnswer());
                ques.setID(treeObject.getQuestion().getID());
                ques.setQuestionDocument(componentQuestion.getQuestionDocument());
                subsection.modifyQuestion(ques);
            }
            
            // Save to file
            manager.saveToFile(record);
            String st ="Question saved successfully!";
            JOptionPane.showMessageDialog(null,st);
        } catch (IOException ex) {
            Logger.getLogger(QuestionForm.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void refreshMainPanel() {
        delegate.getMainPanel().repaint();
        setterFormDelegate.updateUI();
        setterFormDelegate.getSetterFormDelegate().pack();
    }
    
    private int getNumberOfBlank() {
        String originalText = multipleFillin.getQuestionText();
        Pattern pattern = Pattern.compile("\\([0-9]\\)");
        Matcher  matcher = pattern.matcher(originalText);
        int numberOfBlank = 1;
        while (matcher.find()) {
            numberOfBlank++;
        }
        return numberOfBlank;
    }
    
    private void saveCorrectAnswer(int number) {
        String[] answer = multipleFillin.getCorrectAnswerTextPanel().getCorrectAnswer();
        multipleFillin.insertOrUpdateCorrectAnswer(answer, number); 
    }
    
    private void addLinkToQuestionText() {
        int numberOfBlank = getNumberOfBlank();
        HTMLDocument doc = 
                multipleFillin.getHTMLDocument();
        Element paragraph =
            doc.getElement(doc.getDefaultRootElement(), StyleConstants.NameAttribute, HTML.Tag.P);
        String blanksText = "<a href='"+numberOfBlank+"' id='BL"+numberOfBlank+"'> ("+numberOfBlank+")_______</a>&NBSP";
        try {
            doc.insertBeforeEnd(paragraph, blanksText);
        } catch (BadLocationException ex) {
            Logger.getLogger(QuestionForm.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(QuestionForm.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    /**
     * Listener
     */
    
    public void saveButtonDidTap() {
        // validate input
        if (validateInputComponent() == false) return;
        if (this.currentState == SetterFormController.ActionEvent.ADD_EVENT) {
            addQuestionToRecord(treeObject.getRecord());
            // notify the form the process has finished
            try {
                setterFormDelegate.addTreeDidFinish(getQuestionComponent(),
                                            treeObject.getParentNode());
            } catch (Exception e) {
                System.err.print("Error" + e.getMessage());
            }
            // reset the component
            resetInputComponent();
        } else if (this.currentState == SetterFormController.ActionEvent.EDIT_EVENT) {
            editQuestionFromRecord(treeObject.getRecord());
            // notify the form the process has finished
            try {
                setterFormDelegate.editTreeDidFinish(treeObject.getQuestion(),
                                            treeObject.getParentNode());
            } catch (Exception e) {
                System.err.print("Error" + e.getMessage());
            }
        }
    }
    
    public void typeComboButtonDidTap() {
        delegate.getMainPanel().invalidate();
        delegate.getMainPanel().removeAll();
        String selectedItem = (String)delegate.getTypeCombo().getSelectedItem();
        if (selectedItem.equals(MULTIPLE_CHOICE_QUESTION)) {
            delegate.getMainPanel().add(multiple);
        } else if (selectedItem.equals(FILL_IN_BLANK_QUESTION)) {
            delegate.getMainPanel().add(fillin);
        } else if (selectedItem.equals(MULTIPLE_FILL_IN_BLANK_QUESTION)) {
            delegate.getMainPanel().add(multipleFillin);
        }
        refreshMainPanel();
    }
    
    public void sectionItemComboItemDidChange(java.awt.event.ItemEvent evt) {
        if (evt.getStateChange() == ItemEvent.SELECTED){
            if (delegate.getSectionCombo().getItemCount() > 1) {
                // reset input component
                resetInputComponent();
                // change to add
                this.setCurrentState(SetterFormController.ActionEvent.ADD_EVENT);
                // update subsection combo box
                Section section = (Section)delegate.getSectionCombo().getSelectedItem();
                updateSubSectionComboBox(section);
            }
        }
    }
    
    public void deleteQuestionButtonDidTap() {
        try {
            setterFormDelegate.invokeComponent(SetterFormController.ActionEvent.DELETE_EVENT);
        } catch (Exception e) {
            System.err.print("Error : " + e.getMessage());
        }
        // reset the component
        resetInputComponent();
        // change to add
        this.setCurrentState(SetterFormController.ActionEvent.ADD_EVENT);
    }
    
    /**
     * 
     * @param notification 
     */
    
    @Override
    public void addCorrectAnswerDidTap(Object object) {
        if (multipleFillin.getCorrectAnswerPanel().getComponentCount() == 0) {
            multipleFillin.addNewCorrectAnswerPanel();
            refreshMainPanel();
        }
        addLinkToQuestionText();
    }
    
    @Override
    public void hyperlinkTextDidTap(javax.swing.event.HyperlinkEvent evt) {
        if (evt.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
            int number = Integer.parseInt(evt.getDescription());
            // save the previous answer
            saveCorrectAnswer(multipleFillin.getPreviousNumber());
            // get currecnt correct answer if exist
            this.multipleFillin.setCorrectAnswer(number);
            this.multipleFillin.setPreviousNumber(number);
        }
    }
    
    @Override
    public void questionTextDocumentDidChange(DocumentEvent evt) {
        
    }

    @Override
    public void questionTextDocumentDidInsert(DocumentEvent evt) {
        
    }

    @Override
    public void questionTextDocumentDidRemove(DocumentEvent evt) {
        String questionText = multipleFillin.getQuestionText();
        int numberOfBlank = getNumberOfBlank() - 1;
        if (questionText.charAt(questionText.length() - 1) == '_') {
         
        final HTMLDocument doc = multipleFillin.getHTMLDocument();
        final Element link = doc.getElement("BL" + numberOfBlank);
        Element root = doc.getDefaultRootElement();
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    HTMLDocumentPlusRemove.removeElement(doc, link);
                } catch (Exception ex) {
                    Logger.getLogger(QuestionForm.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
          });

        }
    }
    
}
